/*!
 * \file was_ejb.c
 *
 * \brief was ejb 数据包解析
 *
 * All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.\n
 *
 * \version 3.0
 * \author wuwk
 * \date 2016/03/10
 *
 */

#include <stdio.h>
#include <iconv2utf8.h>

#include "corba_comm.h"
#include "was_ejb.h"
#include "ejb_comm.h"

#define GIOP_OP_RESOLVE_INFO      "resolve_complete_info"


/*!
 * 对齐
 *
 * \param *p_st_session_private           (corba_session         session数据)
 * \param *p_st_body_data                 (Frreport_body_data 上报数据)
 *
 * \return FR_SUCC:成功\n
 *         FR_FAIL:失败\n
 *
 */
FR_STATIC int __get_ejb_name(corba_session *p_st_session_private
                           , Frreport_body_data *p_st_body_data)
{
    L7session_corba_private *p_st_private = NULL;
    char *p_key_address = NULL;
    char *p_sharp = NULL;
    char *p_name = NULL;
    char arr_len[5];
    uint32_t *p_i_tmp = NULL;
    uint32_t u32_len = 0;
    int i_len = 0;
    int i_key_addr_remain = 0;
    int i_name_len = 0;
    int i_endianess = 0;

    if (p_st_session_private == NULL || p_st_body_data == NULL
        || p_st_session_private->p_key_address == NULL
        || p_st_session_private->p_st_private == NULL)
        return FR_FAIL;

    p_key_address = p_st_session_private->p_key_address;
    p_st_private = p_st_session_private->p_st_private;

    if (strncmp(p_key_address, "JMBI" , 4) != 0 || p_st_session_private->i_key_addr_len <= 42)
        return FR_SUCC;

    p_key_address += 40;
    i_key_addr_remain = p_st_session_private->i_key_addr_len - 40;

    // 版本
    if (*p_key_address == 1)
    {
        p_key_address += 2;
        i_key_addr_remain -= 2;
    }
    else if (*p_key_address == 2)
    {
        if (i_key_addr_remain < 6)
            return FR_SUCC;

        p_key_address += 6; // 4位hash code
        i_key_addr_remain -= 6;
    }

    // rootKey
    i_len = *p_key_address;

    if (i_key_addr_remain < i_len + 1)
        return FR_SUCC;
    p_key_address += (i_len + 1);
    i_key_addr_remain -= (i_len + 1);

    // oaPrefix
    i_len = *p_key_address;

    if (i_key_addr_remain < i_len + 1)
        return FR_SUCC;
    p_key_address += (i_len + 1);
    i_key_addr_remain -= (i_len + 1);

    if (i_key_addr_remain < 9)
        return FR_SUCC;
    p_key_address += 9; // 4位长度+5
    i_key_addr_remain -= 9;

    if (*p_key_address == 0)
        i_endianess = BYTE_BIG_ENDIAN;
    else
        i_endianess = BYTE_LITTLE_ENDIAN;

    if (i_key_addr_remain < 2)
        return FR_SUCC;
    p_key_address += 2;
    i_key_addr_remain -= 2;

    memcpy(arr_len, p_key_address, 4);
    arr_len[4] = '\0';
    p_i_tmp = (uint32_t *)arr_len;
    if (i_endianess == BYTE_BIG_ENDIAN)
        u32_len = be32toh((uint32_t )*p_i_tmp);
    else
        u32_len = le32toh((uint32_t )*p_i_tmp);

    if (i_key_addr_remain < 4)
        return FR_SUCC;
    p_key_address += 4; //长度
    i_key_addr_remain -= 4;

    if (u32_len != strlen(p_key_address))
        return FR_SUCC;

    p_sharp = strchr(p_key_address, '#');
    if (p_sharp == NULL)
        return FR_SUCC;

    i_name_len = p_sharp - p_key_address;
    p_name = (char *)frmalloc(i_name_len + 1);
    if (p_name == NULL)
        return FR_FAIL;

    snprintf(p_name, i_name_len + 1, "%s", p_key_address);

    // 作为title
    if (p_st_private->p_title)
        frfree(p_st_private->p_title);

    p_st_private->p_title = p_name;

    return FR_SUCC;
}

/*!
 * iiop was ejb响应(string,object)解析
 *
 * \param *p_st_data           (Frbyte_Packet         数据)
 * \param *p_st_body_data      (Frreport_body_data    上报数据)
 * \param *p_key               (char    上报key)
 * \param i_pos                (首位置)
 *
 * \return FR_SUCC:成功\n
 *         FR_FAIL:失败\n
 *
 */
FR_STATIC int __was_resp_object(Frbyte_Packet *p_st_data
                              , Frreport_body_data *p_st_body_data
                              , char *p_key
                              , int i_pos)
{
    char *p_object = NULL;
    char *p_data = NULL;
    char *p_utf8 = NULL;
    unsigned int ui_utf8_len = 0;
    uint32_t u32_chunk = 0;
    uint32_t u32_obj_len = 0;
    uint32_t u32_data_len = 0;
    uint32_t u32_count = 0;
    int i_remain_len = 0;
    int i_ret = 0;

    if (p_st_data == NULL || p_st_body_data == NULL || p_key == NULL)
        return FR_FAIL;

    i_remain_len = bytebuff_remaining(p_st_data);
    if (i_remain_len < 4)
        return FR_FAIL;

    if (bytebuff_peek_int(p_st_data, 4, &u32_chunk, BYTE_BIG_ENDIAN) == FR_FAIL)
        return FR_FAIL;

    // 7f ff ff 02
    if (u32_chunk != 2147483394 && u32_chunk != 2147483402)
        return FR_SUCC;

    bytebuff_skip(p_st_data, 4);

    if (bytebuff_get_int(p_st_data, 4, &u32_obj_len, BYTE_BIG_ENDIAN) == FR_FAIL)
        return FR_FAIL;

    p_object = (char *)frmalloc(u32_obj_len + 1);
    if (p_object == NULL)
        return FR_FAIL;

    if (bytebuff_get_bytes(p_st_data, p_object, u32_obj_len) == FR_FAIL)
    {
        frfree(p_object);
        return FR_FAIL;
    }

    if (u32_obj_len == 35 && strncmp(p_object, CORBA_IDL_STRINGVALUE, 34) == 0)
    {
        frfree(p_object);
        // string
        bytebuff_skip(p_st_data, 1); //对齐

        if (bytebuff_get_int(p_st_data, 4, &u32_data_len, BYTE_BIG_ENDIAN) == FR_FAIL)
            return FR_FAIL;

        p_data = (char *)frmalloc(u32_data_len + 1);
        if (p_data == NULL)
            return FR_FAIL;

        if (bytebuff_get_bytes(p_st_data, p_data, u32_data_len) == FR_FAIL)
        {
            frfree(p_data);
            return FR_FAIL;
        }
        p_data[u32_data_len] = '\0';

        // unicode转utf-8
        i_ret = iconv_to_utf8(p_data, u32_data_len, (char *)"UNICODEBIG", &p_utf8, &ui_utf8_len);
        if (i_ret == 1)
        {
            frfree(p_data);
            frfree(p_utf8);
            return FR_FAIL;
        }
        else if (i_ret == 2)
        {
            frfree(p_data);
            return FR_FAIL;
        }

        frfree(p_data);

        if (frreport_body_l7_add_str(p_st_body_data, p_key, p_utf8) == FR_FAIL)
        {
            frfree(p_utf8);
            return FR_FAIL;
        }
        frfree(p_utf8);
    }
    else if (strncmp(p_object, RMI_ARRAY, 5) == 0)
    {
        // 对齐
        if (__alignment(p_st_data, i_pos, 4) == FR_FAIL)
            return FR_FAIL;

        if (bytebuff_get_int(p_st_data, 4, &u32_count, BYTE_BIG_ENDIAN) == FR_FAIL)
        {
            frfree(p_object);
            return FR_FAIL;
        }

        switch (*(p_object+5))
        {
            case 'B':
                if (ejb_rtn_byte_array(p_st_data, p_st_body_data, u32_count, p_key) == FR_FAIL)
                    goto err;
                break;
            case 'C':
                if (ejb_rtn_char_array(p_st_data, p_st_body_data, u32_count, p_key) == FR_FAIL)
                    goto err;
                break;
            case 'S':
                if (ejb_rtn_short_array(p_st_data, p_st_body_data, u32_count, p_key) == FR_FAIL)
                    return FR_FAIL;
                break;
            case 'I':
                if (ejb_rtn_int_array(p_st_data, p_st_body_data, u32_count, p_key) == FR_FAIL)
                    goto err;
                break;
            case 'J':
                if (ejb_rtn_long_array(p_st_data, p_st_body_data, u32_count, p_key) == FR_FAIL)
                    goto err;
                break;
            case 'F':
                if (ejb_rtn_float_array(p_st_data, p_st_body_data, u32_count, p_key) == FR_FAIL)
                    goto err;
                break;
            case 'D':
                if (ejb_rtn_double_array(p_st_data, p_st_body_data, u32_count, p_key) == FR_FAIL)
                    goto err;
                break;
            case 'Z':
                if (ejb_rtn_boolean_array(p_st_data, p_st_body_data, u32_count, p_key) == FR_FAIL)
                    goto err;
                break;
            case 'L':
                if (strncmp(p_object + 6, RMI_JAVA_STRING, strlen(RMI_JAVA_STRING)) == 0)
                {
                    if (ejb_rtn_string_array(p_st_data, p_st_body_data, u32_count, p_key, i_pos, IS_WAS) == FR_FAIL)
                        goto err;
                }
                else if (strncmp(p_object + 6, RMI_JAVA_OBJECT, strlen(RMI_JAVA_OBJECT)) == 0)
                {
                    i_remain_len = bytebuff_remaining(p_st_data);
                    // 上报
                    p_data = (char *)frmalloc((unsigned int)i_remain_len);
                    if(p_data == NULL)
                        goto err;

                    if (frreport_body_l7_add_bin(p_st_body_data, p_key, p_data, i_remain_len) == FR_FAIL)
                    {
                        frfree(p_data);
                        goto err;
                    }

                    frfree(p_data);

                }
                break;
            default:
                break;
        }
        frfree(p_object);
    }
    else
    {
        frfree(p_object);
        return FR_SUCC;
    }

    return FR_SUCC;

err:
    if (p_object)
        frfree(p_object);

    return FR_FAIL;
}

/*!
 * iiop was ejb 请求解析
 *
 * \param *p_st_session_private        (corba_session         私有数据)
 * \param *p_st_body_data              (Frreport_body_data    上报数据)
 *
 * \return FR_SUCC:成功\n
 *         FR_FAIL:失败\n
 *
 */
int was_ejb_parse_req(corba_session *p_st_session_private
                    , Frreport_body_data *p_st_body_data)
{
    L7session_corba_private *p_st_private = NULL;

    if (p_st_session_private == NULL || p_st_body_data == NULL || p_st_session_private->p_st_private == NULL)
        return FR_FAIL;

    p_st_private = p_st_session_private->p_st_private;

    if (p_st_private->p_title != NULL && strcmp(p_st_private->p_title, GIOP_OP_RESOLVE_INFO) == 0)
        return FR_SUCC;

    // 取得EJB名作为title
    if (__get_ejb_name(p_st_session_private, p_st_body_data) == FR_FAIL)
        return FR_FAIL;

    if (p_st_session_private->p_was_function == NULL)
        return FR_FAIL;

    // ejb function上报
    if (frreport_body_l7_add_str(p_st_body_data, EJB_FUNC, p_st_session_private->p_was_function) == FR_FAIL)
        return FR_FAIL;

    return FR_SUCC;
}

/*!
 * iiop was ejb 响应解析
 *
 * \param *p_st_session_private        (corba_session         私有数据)
 * \param *p_st_data                   (Frbyte_Packet         数据)
 * \param *p_st_body_data              (Frreport_body_data    上报数据)
 *
 * \return FR_SUCC:成功\n
 *         FR_FAIL:失败\n
 *
 */
int was_ejb_parse_resp(corba_session *p_st_session_private
                     , Frbyte_Packet *p_st_data
                     , Frreport_body_data *p_st_body_data)
{
    char *p_data = NULL;
    char arr_key[64];
    int i_remain_len = 0;
    int i_ret = 0;

    if (p_st_session_private == NULL || p_st_data == NULL || p_st_body_data == NULL)
        return FR_FAIL;

    i_remain_len = bytebuff_remaining(p_st_data);
    snprintf(arr_key, sizeof(arr_key), "%s.1.1", EJB_FUNC_RESP);

    switch (i_remain_len)
    {
        case 1:
        case 2:
        case 3: // char
        case 4:
        case 8:
            p_data = (char *)frmalloc(i_remain_len + 1);
            if (p_data == NULL)
                return FR_FAIL;

            if (bytebuff_get_bytes(p_st_data, p_data, i_remain_len) == FR_FAIL)
            {
                frfree(p_data);
                return FR_FAIL;
            }

            if (frreport_body_l7_add_bin(p_st_body_data, arr_key, p_data, i_remain_len) == FR_FAIL)
            {
                frfree(p_data);
                return FR_FAIL;
            }
            frfree(p_data);

            break;
        default:
            p_st_session_private->i_pos = bytebuff_getPosition(p_st_data);

            i_ret = __was_resp_object(p_st_data, p_st_body_data, arr_key, p_st_session_private->i_pos);
            if (i_ret == FR_FAIL)
                return FR_FAIL;

            break;
    }

    return FR_SUCC;
}
